//
//  SUBrain.m
//  RPN Calculator
//
//  Created by SunnyUp on 13-1-7.
//  Copyright (c) 2013年 SunnyUp. All rights reserved.
//

#import "SUBrain.h"

@interface SUBrain()
@property (nonatomic, strong) NSMutableArray *programStack;
@end

@implementation SUBrain

@synthesize programStack = _programStack;

- (NSMutableArray *) programStack
{
    if(_programStack == nil) _programStack = [[NSMutableArray alloc] init];
    return _programStack;
}

- (id)program
{
    //when we try to run a program, we do not pop object off our programStack,
    // but we create a temporary copy of the current programStack,
    // we do the calculating thing by poping object off the temporary copy,
    // which makes the programStack keeping recording the full history.
    return [self.programStack copy];
}

+ (NSString *) descriptionOfProgram:(id)program
{
    return @"to be implemented in Assignment #2";
}

- (void) pushOperand: (double)operand
{
    [self.programStack addObject:[NSNumber numberWithDouble:operand]];
}

+ (double) popOperandOffProgramStack:(NSMutableArray *)stack
{
    //as we do the poping off thing on stack(in the arrgument) but not on the programStack(in the instance),
    // we define this method to be a class method but not a instance method
    double result = 0;
    
    id topOfStack = [stack lastObject];
    if(topOfStack)
        [stack removeLastObject];
    
    if([topOfStack isKindOfClass:[NSNumber class]])
    {
        return [topOfStack doubleValue];
    }
    else if([topOfStack isKindOfClass:[NSString class]])
    {
        NSString *operation = topOfStack;
        if([operation isEqualToString:@"+"])
        {
            result = [self popOperandOffProgramStack:stack] + [self popOperandOffProgramStack:stack];
        }
        else if([operation isEqualToString:@"-"])
        {
            double firstOperand = [self popOperandOffProgramStack:stack];
            result = [self popOperandOffProgramStack:stack] - firstOperand;
        }
        else if([operation isEqualToString:@"*"])
        {
            result = [self popOperandOffProgramStack:stack] * [self popOperandOffProgramStack:stack];
        }
        else if([operation isEqualToString:@"/"])
        {
            double firstOperand = [self popOperandOffProgramStack:stack];
            if(firstOperand)
                result = [self popOperandOffProgramStack:stack] / firstOperand;
            else
                result = firstOperand;
        }
        else if ([operation isEqualToString:@"sin"])
        {
            result = sin([self popOperandOffProgramStack:stack]);
        }
        else if ([operation isEqualToString:@"cos"])
        {
            result = cos([self popOperandOffProgramStack:stack]);
        }
        else if ([operation isEqualToString:@"sqrt"])
        {
            result = sqrt([self popOperandOffProgramStack:stack]);
        }
        else if ([operation isEqualToString:@"log"])
        {
            result = log([self popOperandOffProgramStack:stack]);
        }
        else if ([operation isEqualToString:@"π"])
        {
            result = M_PI;
        }
        else if ([operation isEqualToString:@"e"])
        {
            result = M_E;
        }
        else if ([operation isEqualToString:@"+ / -"])
        {
            result = (-1) * [self popOperandOffProgramStack:stack];
        }
    }
    
    return result;
}

+ (double)runProgram:(id)program
{
    NSMutableArray *stack;
    if([program isKindOfClass:[NSArray class]])
        stack = [program mutableCopy];
    
    return [self popOperandOffProgramStack:stack];
}

- (double) performOperation: (NSString *)operation
{
    [self.programStack addObject:operation];
    return [[self class] runProgram:self.program];
}

- (void) clear
{
    [self.programStack removeAllObjects];
}

@end
